package com.wmh.baseservice.common.timer;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.wmh.baseservice.admin.pojo.AdProfit;
import com.wmh.baseservice.admin.service.AdProfitService;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.utils.CommUtil;
import com.wmh.baseservice.common.utils.LogUtil;
import com.wmh.baseservice.common.wechat.ma.template.WxTemplateMsgUtils;
import com.wmh.baseservice.merchant.pojo.*;
import com.wmh.baseservice.merchant.service.*;
import com.wmh.baseservice.system.pojo.SysMessage;
import com.wmh.baseservice.system.pojo.SysParams;
import com.wmh.baseservice.system.service.SysMessageService;
import com.wmh.baseservice.system.service.SysParamsService;
import com.wmh.baseservice.user.pojo.*;
import com.wmh.baseservice.user.service.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class ScheduledTime {

    @Resource
    private SysParamsService sysParamsService;
    @Resource
    private UsGroupGoodsOrderService usGroupGoodsOrderService;
    @Resource
    private UsVegetableOrderService usVegetableOrderService;
    @Resource
    private UsGoodsOrderService usGoodsOrderService;
    @Resource
    private UsRentOrderService usRentOrderService;
    @Resource
    private MerchantPlotRentService merchantPlotRentService;
    @Resource
    private MerchantPlotRegionService merchantPlotRegionService;
    @Resource
    private MerchantInfoService merchantInfoService;
    @Resource
    private MerchantGroupGoodsService merchantGroupGoodsService;
    @Resource
    private MerchantGroupGoodsPriceService merchantGroupGoodsPriceService;
    @Resource
    private UsInfoService usInfoService;
    @Resource
    private UsIncomeExpendService usIncomeExpendService;
    @Resource
    private MerchantIncomeExpendService merchantIncomeExpendService;
    @Resource
    private AdProfitService adProfitService;
    @Resource
    private SysMessageService sysMessageService;
    @Resource
    private UsParentOrderService usParentOrderService;


    /**
     * 每天凌晨00：01执行一次，将所有团购商品标记为未结算
     * 已过失
     */
    // @Scheduled(cron = "0 1 0 * * ? ")
    // @Transactional(rollbackFor = Exception.class)
    public void tagRemark() {
        UpdateWrapper<MerchantGroupGoods> updateWrapper = new UpdateWrapper<MerchantGroupGoods>().set(MerchantGroupGoods.REMARK, "0");
        if (!merchantGroupGoodsService.update(updateWrapper)) {
            throw new ServiceException("定时标记团购未结算失败");
        }
    }

    /**
     * 每小时执行一次，查询已到时间的团购，并且结算退差价
     */
//    @Scheduled(cron = "0 0 */1 * * ?")
//    @Transactional(rollbackFor = Exception.class)
/*    public void settlement() {
        Map<String, Object> map = new HashMap<>();
        // 查询到截至时间的团购商品  = usGroupGoodsOrderService.selectSettlement();
        List<MerchantGroupGoods> merchantGroupGoods = null;
        if (merchantGroupGoods.size() != 0) {
            //修改备注为当天已结算
            merchantGroupGoods.forEach(item -> item.setRemark("1"));
            if (!merchantGroupGoodsService.updateBatchById(merchantGroupGoods)) {
                throw new ServiceException("修改团购商品结算状态错误:" + merchantGroupGoods.toString());
            }
            //查出该商品所有订单
            merchantGroupGoods.forEach(item -> {
                //获取当前商品已达到的优惠档位
                List<UsGroupGoodsOrder> usGroupGoodsOrders = usGroupGoodsOrderService.settlementOrderList(item.getId());
                usGroupGoodsOrders.forEach(order -> {
                    //初始化数据
                    int totalCount;
                    final BigDecimal[] totalProfit = {new BigDecimal(0)};
                    List<UsIncomeExpend> usIncomeExpendList = new ArrayList<>();
                    List<MerchantIncomeExpend> merchantIncomeExpendList = new ArrayList<>();

                    //查询用户和商家，给后面返还余额和商家余额扣减用
                    UsInfo usInfo = usInfoService.getByIdForUpdate(order.getUsId());
                    MerchantInfo merchantInfo = merchantInfoService.getByIdForUpdate(order.getMerchantId());

                    if (CommUtil.checkNull(order.getSpecId())) {
                        map.put("specId", order.getSpecId());
                        totalCount = usGroupGoodsOrderService.totalCount(map);

                        //获取优惠档位列表，对比是否达到该档位
                        List<MerchantGroupGoodsPrice> merchantGroupGoodsPrices = merchantGroupGoodsPriceService.listForUpdate(new QueryWrapper<MerchantGroupGoodsPrice>()
                                .eq(MerchantGroupGoodsPrice.GROUP_GOODS_ID, order.getGroupGoodsId()).eq(MerchantGroupGoodsPrice.SPEC_ID, order.getSpecId())).stream()
                                .sorted(Comparator.comparing(MerchantGroupGoodsPrice::getSuccessGear)).collect(Collectors.toList());
                        int finalTotalCount = totalCount;
                        merchantGroupGoodsPrices.forEach(priceGear -> {
                            //当前规格总购买量达到该优惠档位并且用户实际支付价格低于该档位优惠价格
                            if (finalTotalCount >= priceGear.getSuccessGear() && order.getRealPrice().compareTo(priceGear.getDiscountPrice()) < 0) {
                                //累积到差价中(用户实际支付价格-当前优惠价格)
                                BigDecimal usProfit = order.getRealPrice().subtract(priceGear.getDiscountPrice());
                                totalProfit[0] = totalProfit[0].add(usProfit);
                                //添加用户收入流水
                                UsIncomeExpend usIncomeExpend = new UsIncomeExpend().setUsId(order.getUsId()).setMoney(usProfit).setOrderNum(order.getOrderNum()).setStatus(1).setType(1);
                                usIncomeExpendList.add(usIncomeExpend);
                                //添加商家支出流水
                                MerchantIncomeExpend merchantIncomeExpend = new MerchantIncomeExpend().setOrderNum(order.getOrderNum()).setMerchantId(order.getMerchantId()).setMoney(usProfit).setStatus(1);
                                merchantIncomeExpendList.add(merchantIncomeExpend);
                            }
                        });
                    } else {
                        map.put("groupGoodsId", order.getGroupGoodsId());
                        totalCount = usGroupGoodsOrderService.totalCount(map);
                        List<MerchantGroupGoodsPrice> merchantGroupGoodsPrices = merchantGroupGoodsPriceService.listForUpdate(new QueryWrapper<MerchantGroupGoodsPrice>()
                                .eq(MerchantGroupGoodsPrice.GROUP_GOODS_ID, order.getGroupGoodsId()));
                        int finalTotalCount = totalCount;
                        merchantGroupGoodsPrices.forEach(priceGear -> {
                            //当前规格总购买量达到该优惠档位并且用户实际支付价格低于该档位优惠价格
                            if (finalTotalCount >= priceGear.getSuccessGear() && order.getRealPrice().compareTo(priceGear.getDiscountPrice()) < 0) {
                                //累积到差价中(用户实际支付价格-当前优惠价格)
                                BigDecimal usProfit = order.getRealPrice().subtract(priceGear.getDiscountPrice());
                                totalProfit[0] = totalProfit[0].add(usProfit);
                                //添加用户收入流水
                                UsIncomeExpend usIncomeExpend = new UsIncomeExpend().setUsId(order.getUsId()).setMoney(usProfit).setOrderNum(order.getOrderNum()).setStatus(1).setType(1);
                                usIncomeExpendList.add(usIncomeExpend);
                                //添加商家支出流水
                                MerchantIncomeExpend merchantIncomeExpend = new MerchantIncomeExpend().setOrderNum(order.getOrderNum()).setMerchantId(order.getMerchantId()).setMoney(usProfit).setStatus(1);
                                merchantIncomeExpendList.add(merchantIncomeExpend);
                            }
                        });
                    }

                    //结果提交(用户收入商家支出订单差价回写)
                    usInfo.setBalance(usInfo.getBalance().add(totalProfit[0]));
                    merchantInfo.setBalance(merchantInfo.getBalance().subtract(totalProfit[0]));
                    order.setCashBack(totalProfit[0]);
                    if (!usInfoService.updateById(usInfo)) {
                        throw new ServiceException(usInfo.toString());
                    }
                    if (!merchantInfoService.updateById(merchantInfo)) {
                        throw new ServiceException(merchantInfo.toString());
                    }
                    if (!usIncomeExpendService.saveBatch(usIncomeExpendList)) {
                        throw new ServiceException(usIncomeExpendList.toString());
                    }
                    if (!merchantIncomeExpendService.saveBatch(merchantIncomeExpendList)) {
                        throw new ServiceException(merchantIncomeExpendList.toString());
                    }
                    if (!usGroupGoodsOrderService.updateById(order)) {
                        throw new ServiceException(order.toString());
                    }
                });
            });
        }
    }*/

    /**
     * 15分钟查一次订单是否超时，并取消订单
     */
    @Scheduled(cron = "0 0/15 * * * ?")
    public void cancelOrder() {
        SysParams sysParams = sysParamsService.getByIdForUpdate(6L);
        Long value = Long.parseLong(sysParams.getValue());
        //团购订单
        usGroupGoodsOrderService.cancelOrder(value);
        //普通订单
        usGoodsOrderService.cancelOrder(value);
        //租赁订单
        usRentOrderService.cancelOrder(value);
        //果蔬订单
        usVegetableOrderService.cancelOrder(value);
        //果蔬购物车
        usParentOrderService.cancelOrder(value);

    }

    /**
     * 30分钟执行一次，自动收货
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    public void autoDeliver() {
        SysParams vegetable = sysParamsService.getByIdForUpdate(12L);
        SysParams groupGoods = sysParamsService.getByIdForUpdate(13L);
        List<UsVegetableOrder> usVegetableOrders = usVegetableOrderService.autoDeliver(vegetable.getValue());
        List<UsGroupGoodsOrder> usGroupGoodsOrders = usGroupGoodsOrderService.autoDeliver(groupGoods.getValue());
        usVegetableOrders.forEach(item -> {
            item.setStatus(3);
            usVegetableOrderService.confirm(item);
        });
        usGroupGoodsOrders.forEach(order -> {
            if (order.getType() != 0) {
                //快递、配送单
                order.setStatus(5);
            } else {
                //自提单
                order.setStatus(4);
            }
            order.setDeliveryTime(new Date());
            usGroupGoodsOrderService.theGoods(order);
        });
    }

    /**
     * 每天凌晨更新一次租赁合同时间，如果为0则说明到期，将该区域转回给原商家并且修改合同和冻结商家状态(如果商家是租赁入驻的)
     */
    @Scheduled(cron = "0 0 0 * * ?")
    @Transactional(rollbackFor = Exception.class)
    public void updateRegionRent() {
        final int[] success = {0};
        final int[] error = {0};
        List<MerchantPlotRent> merchantPlotRents = merchantPlotRentService.listForUpdate(new QueryWrapper<MerchantPlotRent>().eq(MerchantPlotRent.STATUS, 1));
        merchantPlotRents.forEach(item -> {
            item.setDay(item.getDay() - 1);
            if (item.getDay() <= 2) {
                //提醒用户，发送订阅消息
                UsInfo usInfo = usInfoService.getByIdForUpdate(item.getRentUsId());
                MerchantInfo merchantInfo = merchantInfoService.getByIdForUpdate(item.getRawMerchantId());
                JSONObject object = new JSONObject(true);
                object.put("number3", item.getDay().toString());
                object.put("thing4", merchantInfo.getName());
                object.put("thing5", "您租的区域即将到期，请尽快进入小程序续期");
                WxTemplateMsgUtils.rentNoticePickGoods(usInfo.getOpenId(), object);
                MerchantPlotRegion merchantPlotRegion = merchantPlotRegionService.getByIdForUpdate(item.getRegionId());
                //发送小程序消息
                SysMessage sysMessage = new SysMessage();
                sysMessage.setUsId(usInfo.getId()).setTitle("您的承租区域即将到期").setContent(
                        String.format("您的%s区域还剩下%s天使用时间，到期后如没有续费，那么该区域将转回原商家，此区域所产生的摘种收益也不再归你所有，" +
                                "为了您的收益，建议您尽快到租赁订单页面进行续租操作", merchantPlotRegion.getName(), item.getDay())).setStatus(0);
                if (!sysMessageService.save(sysMessage)) {
                    throw new ServiceException();
                }
            }
            if (item.getStatus() != -1) {
                if (update(item) == 0) {
                    success[0] += 1;
                } else {
                    error[0] += 1;
                }
            }
        });

        LogUtil.info(String.format("成功更新合同%s个", success[0]));
        LogUtil.info(String.format("失败更新合同%s个", error[0]));
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int update(MerchantPlotRent merchantPlotRent) {
        if (merchantPlotRent.getDay() <= 0) {
            //修改合同状态为已过期转回
            merchantPlotRent.setStatus(-1);
            //区域改为原商家,状态返回为出租中
            MerchantPlotRegion merchantPlotRegion = merchantPlotRegionService.getByIdForUpdate(merchantPlotRent.getRegionId());
            merchantPlotRegion.setMerchantId(merchantPlotRent.getRawMerchantId()).setStatus(1);
            //判断是否需要退还押金，如果该合同已经有该区域订单的退押金流水，那么不退押金
            List<UsRentOrder> usRentOrders = usRentOrderService.listForUpdate(new QueryWrapper<UsRentOrder>()
                    .eq(UsRentOrder.RENT_ID, merchantPlotRent.getId()).eq(UsRentOrder.US_ID, merchantPlotRent.getRentUsId())
                    .eq(UsRentOrder.REGION_ID, merchantPlotRent.getRegionId()).eq(UsRentOrder.STATUS, 1).eq(UsRentOrder.TYPE,1));

            //TODO 判断是否需要退还押金，和每笔订单具体的退款金额
            boolean hasDeposit = false;
            if (merchantPlotRent.getHasDeposit() == 0) {
                //标注为已退押金，下次再循环则不退了
                merchantPlotRent.setHasDeposit(1);
                hasDeposit = true;
            }

            if (hasDeposit) {
                //退还押金,土地原商家退到租赁用户余额中,因为提现时做了限制，所以这里无需判断商家余额是否足够
                MerchantInfo rawMerchantInfo = merchantInfoService.getByIdForUpdate(merchantPlotRent.getRawMerchantId());
                UsInfo rentUsInfo = usInfoService.getByIdForUpdate(merchantPlotRent.getRentUsId());

                //获取押金，离当前时间最近的正常租订单
                List<UsRentOrder> depositOrder = usRentOrders.stream().sorted(Comparator.comparing(UsRentOrder::getCreateTime)
                        .reversed()).collect(Collectors.toList());
                if (depositOrder.size() == 0) {
                    LogUtil.error("租赁合同更新失败:租赁订单押金为空,合同id为:{}", merchantPlotRent.getId());
                    return -1;
                }
                UsRentOrder usRentOrder = depositOrder.get(0);
                BigDecimal deposit = JSONObject.parseObject(usRentOrder.getSnapshot()).getBigDecimal("deposit");

                //商家余额减少，用户余额添加
                rawMerchantInfo.setBalance(rawMerchantInfo.getBalance().subtract(deposit));
                rentUsInfo.setBalance(rentUsInfo.getBalance().add(deposit));
                //原商家支出流水，用户收入流水
                MerchantIncomeExpend merchantIncomeExpend = new MerchantIncomeExpend().setStatus(-1).setRemark("退还租赁用户押金")
                        .setMoney(deposit).setOrderNum(usRentOrder.getOrderNum()).setMerchantId(rawMerchantInfo.getId());
                UsIncomeExpend usIncomeExpend = new UsIncomeExpend().setType(1).setStatus(1)
                        .setMoney(deposit).setRemark("租赁用户押金退还").setUsId(rentUsInfo.getId());
                //提交事务
                if (!merchantInfoService.updateById(rawMerchantInfo)) {
                    LogUtil.error("租赁合同更新失败:更新商家余额失败,合同id为:{}", merchantPlotRent.getId());
                    return -1;
                }
                if (!usInfoService.updateById(rentUsInfo)) {
                    LogUtil.error("租赁合同更新失败:更新用户余额失败,合同id为:{}", merchantPlotRent.getId());
                    return -1;
                }
                if (!merchantIncomeExpendService.save(merchantIncomeExpend)) {
                    LogUtil.error("租赁合同更新失败:更新商家支出失败,合同id为:{}", merchantPlotRent.getId());
                    return -1;
                }
                if (!usIncomeExpendService.save(usIncomeExpend)) {
                    LogUtil.error("租赁合同更新失败:更新用户收入失败,合同id为:{}", merchantPlotRent.getId());
                    return -1;
                }

            }


            //冻结租赁商家账号(暂不冻结)
            MerchantInfo merchantInfo = merchantInfoService.getByIdForUpdate(merchantPlotRent.getRentMerchantId());
            if (merchantInfo.getType() == 2) {
                merchantInfo.setStatus(1);
                if (!merchantInfoService.updateById(merchantInfo)) {
                    LogUtil.error("租赁合同更新失败:商家信息修改错误,合同id为:{}", merchantPlotRent.getId());
                    return -1;
                }
            }
            if (!merchantPlotRegionService.updateById(merchantPlotRegion)) {
                LogUtil.error("租赁合同更新失败:商家土地区域信息修改错误,合同id为:{}", merchantPlotRent.getId());
                return -1;
            }
        }
        if (!merchantPlotRentService.updateById(merchantPlotRent)) {
            LogUtil.error("租赁合同更新失败:商家土地租赁合同修改错误,合同id为:{}", merchantPlotRent.getId());
            return -1;
        }
        return 0;
    }

    /**
     * 每天凌晨00：05执行一次，结算所有已完成交易且大于售后期的订单的推广佣金
     * 推广佣金之所以要在这个时候结算是为了保证商家余额里面有足够的钱可以付推广佣金
     */
    @Scheduled(cron = "0 5 0 * * ? ")
    @Transactional(rollbackFor = Exception.class)
    public void settleGroupGoodsCommission() {
        //查出所有大于售后期并且交易已完成（无申请售后的订单）
        SysParams sysParams = sysParamsService.getByIdForUpdate(8L);
        List<UsGroupGoodsOrder> usGroupGoodsOrders =
                usGroupGoodsOrderService.getSettleTheCommissionOrderList(sysParams.getValue())
                        .stream().filter(e -> e.getHasCommission() == -1 || e.getHasCommission() == 0).collect(Collectors.toList());
        // 准备用户流水 和 商家流水
        List<UsIncomeExpend> usIncomeExpendList = new ArrayList<>();
        List<MerchantIncomeExpend> merchantIncomeExpendList = new ArrayList<>();
        usGroupGoodsOrders.forEach(item -> {
            //判断是否有上级推广佣金
            MerchantGroupGoods nowGoods = merchantGroupGoodsService.getByIdForUpdate(item.getGroupGoodsId());
            if (CommUtil.checkNull(nowGoods.getCommission())) {
                // 得到当前订单所属的用户
                UsInfo usInfo = usInfoService.getByIdForUpdate(item.getUsId());
                // 判断用户是否存在 , 并是否存在上级 默认-1 为 没有邀请人
                if (CommUtil.checkNull(usInfo) && usInfo.getInviteId() != -1) {

                    // 获得当前商品佣金
                    BigDecimal commission = nowGoods.getCommission();
                    // 获取当前商家信息
                    MerchantInfo nowShop = merchantInfoService.getByIdForUpdate(nowGoods.getMerchantId());

                    // 检查商家当前资金是否足以是否佣金
                    if (nowShop.getBalance().add(nowShop.getMargin()).compareTo(commission) > 0) {
                        // 获得商家余额 判断当前余额是否足以支付佣金 不足够 保证金补
                        BigDecimal balance = nowShop.getBalance();
                        if (commission.compareTo(balance) < 0) {
                            // 得到差值 保证金补充
                            BigDecimal subtract = commission.subtract(balance);
                            // 减少并设置保证金
                            nowShop.setMargin(nowShop.getMargin().subtract(subtract));
                            // 添加商家支出流水
                            merchantIncomeExpendList.add(new MerchantIncomeExpend()
                                    .setMerchantId(item.getMerchantId()).setMoney(subtract)
                                    .setStatus(-1).setOrderNum(item.getOrderNo()).setRemark("扣除保证金 - 团购商品佣金 : " + item.getGroupGoodsId()));
                        }
                        // 减去商家需要支付的余额
                        nowShop.setBalance(nowShop.getBalance().subtract(balance));
                        // 添加商家支出流水
                        merchantIncomeExpendList.add(new MerchantIncomeExpend()
                                .setMerchantId(item.getMerchantId()).setMoney(balance)
                                .setStatus(-1).setOrderNum(item.getOrderNo()).setRemark("扣除余额 - 团购商品用户返现"));
                        // 得到当前佣金需要发放的用户
                        UsInfo nowUs = usInfoService.getByIdForUpdate(usInfo.getInviteId());
                        // 对当前用户余额添加佣金
                        nowUs.setBalance(nowUs.getBalance().subtract(commission));

                        // 修改用户冻结流水为正常流水
                        UsIncomeExpend freezeIncome = usIncomeExpendService.getOneForUpdate(
                                new QueryWrapper<UsIncomeExpend>()
                                        .eq(UsIncomeExpend.ORDER_NUM, item.getOrderNo())
                                        .eq(UsIncomeExpend.REMARK, "团购商品佣金")
                                        .eq(UsIncomeExpend.HAS_FREEZE, -1)
                                        .eq(UsInfo.ID, nowUs.getId()));
                        if (CommUtil.checkNull(freezeIncome)) {
                            freezeIncome.setHasFreeze(1);
                        }
                        // 添加至流水
                        usIncomeExpendList.add(freezeIncome);

                        // 保存发放佣金余额用户余额
                        if (!usInfoService.updateById(nowUs)) {
                            throw new ServiceException();
                        }
                        // 修改商家信息
                        if (!merchantInfoService.updateById(nowShop)) {
                            throw new ServiceException();
                        }
                        // 设置订单推广金结算状态
                        usGroupGoodsOrderService.updateById(item.setHasCommission(1));
                    } else {
                        /* 商家资金不足以结算资金 则设置订单 佣金结算状态为 -1 订单已完成但没有结算佣金*/
                        if (item.getHasCommission() != -1) {
                            usGroupGoodsOrderService.updateById(item.setHasCommission(-1));
                        }
                    }
                }
            }
        });
        if (merchantIncomeExpendList.size() > 0 && !merchantIncomeExpendService.saveBatch(merchantIncomeExpendList)) {
            throw new ServiceException();
        }
        if (usIncomeExpendList.size() > 0 && !usIncomeExpendService.saveOrUpdateBatch(usIncomeExpendList)) {
            throw new ServiceException();
        }

    }

    /**
     * 每天凌晨 1 点执行 结算所有已完成 无不在售后中 且没有 结算商家收益 或 收益结算失败的 订单
     */
    @Scheduled(cron = "0 0 1 * * ? ")
    @Transactional(rollbackFor = Exception.class)
    public void settleGroupGoodsEarnings() {
        SysParams sysParams = sysParamsService.getByIdForUpdate(8L);

        // 得到当前可结算的订单
        List<UsGroupGoodsOrder> orderList = usGroupGoodsOrderService.getCanSettleEarningsOrderList(sysParams.getValue());
        for (UsGroupGoodsOrder order : orderList) {
            // 得到当前商家信息对象
            MerchantInfo nowShop = merchantInfoService.getByIdForUpdate(order.getMerchantId());
            if (nowShop == null) {
                LogUtil.warn("订单结算 - 商家收益 - 结算失败 : 不存在的商家id : {} ", order.getMerchantId());
                break;
            }
            // 判断商家保证是否足够
            if (nowShop.getMargin().compareTo(new BigDecimal(0)) < 0) {
                // 不足够修改订单状态
                order.setHasSettlement(-1);
                break;
            }
            // 设置商家余额为 当前余额 + 订单实付价格
            if (!merchantInfoService.updateById(nowShop.setBalance(nowShop.getBalance().add(order.getRealPrice())))) {
                LogUtil.warn("订单结算 - 商家收益 - 修改商家余额失败 : 商家id : {} ", order.getMerchantId());
                break;
            }
            // 结算成功修改订单状态 , 并添加商家流水
            if (!usGroupGoodsOrderService.updateById(order.setHasSettlement(1))) {
                LogUtil.warn("订单结算 - 商家收益 - 修改订单状态为结算成功失败 : 商家id : {} 订单号: {}", order.getMerchantId(), order.getOrderNo());
            }
            if (!merchantIncomeExpendService.save(new MerchantIncomeExpend()
                    .setMerchantId(order.getMerchantId()).setMoney(order.getRealPrice())
                    .setOrderNum(order.getOrderNo()).setStatus(1).setRemark("团购商品收益结算"))) {
                LogUtil.warn("订单结算 - 商家收益 - 保存商家流水失败  : 商家id : {} ", order.getMerchantId());
            }
        }
    }

    /**
     * 每月月底结算推广佣金
     * 规则：1、该用户推广商家达到x家（系统设置）
     * 2、所有商家当月流水大于y，小于y忽略不计，然后按照比例结算给该用户
     */
    @Scheduled(cron = "0 0 0 L * ?")
    @Transactional(rollbackFor = Exception.class)
    public void promoteCommission() {
        int promoteCount = Integer.parseInt(sysParamsService.getByIdForUpdate(14L).getValue());
        BigDecimal promoteMoney = new BigDecimal(sysParamsService.getByIdForUpdate(15L).getValue());
        BigDecimal promoteCost = new BigDecimal(sysParamsService.getByIdForUpdate(16L).getValue());
        List<UsInfo> usInfos = usInfoService.listForUpdate(new QueryWrapper<UsInfo>().isNotNull(UsInfo.MERCHANT_ID)
                .ne(UsInfo.INVITE_ID, -1)
                .groupBy(UsInfo.INVITE_ID));

        usInfos.forEach(usInfo -> {
            //当月邀请商家数量是否达标
            List<Long> merchants = usInfoService.promoteCommission(usInfo.getId());
            if (merchants.size() >= promoteCount) {
                //商家当月总流水是否达标
                BigDecimal sum = usGroupGoodsOrderService.promoteCommission(merchants);
                if (sum.compareTo(promoteMoney) >= 0) {
                    //达标后按照比例奖励给用户
                    BigDecimal profit = sum.multiply(promoteCost);
                    //平台支出流水
                    AdProfit adProfit = new AdProfit().setOrigin("用户推广达标奖励").setMoney(profit).setStatus(-1);
                    //用户收入流水
                    UsIncomeExpend usIncomeExpend = new UsIncomeExpend().setHasFreeze(1).setMoney(profit).setType(1)
                            .setUsId(usInfo.getId()).setRemark("本月推广佣金").setStatus(1);
                    //用户余额添加
                    usInfo.setBalance(usInfo.getBalance().add(profit));
                    //发送消息
                    SysMessage sysMessage = new SysMessage().setTitle("您本月的推广收益已到账").setUsId(usInfo.getId())
                            .setContent("本月共推广" + merchants.size() + "位商家入驻，共得佣金:" + profit.toString()
                                    + "元,已转入您的余额中，请注意查收");

                    //提交事务
                    if (!adProfitService.save(adProfit)) {
                        throw new ServiceException();
                    }
                    if (!usIncomeExpendService.save(usIncomeExpend)) {
                        throw new ServiceException();
                    }
                    if (!usInfoService.updateById(usInfo)) {
                        throw new ServiceException();
                    }
                    if (!sysMessageService.save(sysMessage)) {
                        throw new ServiceException();
                    }
                }
            }
        });
    }
}
